/*
* Author:  Greg Nowak and Vaibhav Sharma
* Michigan State University
* 
* This is the implementation of the NFC Wireless Sensor Network Application
*/
#include "Timer.h"  /* For timer control */
#include "printf.h"
#include "NFCWireless.h"
#include "Msp430Adc12.h"
module NFCWirelessC
{
 	uses interface Leds;
  	uses interface Timer<TMilli> as ReceiveTimer;  /* Sends all data in flash */
  	uses interface Boot;
	uses interface LogRead;
	uses interface LogWrite;
    uses interface Packet;
    uses interface AMPacket;
    uses interface AMSend;
    uses interface Receive;
    uses interface SplitControl as AMControl;
}
implementation
{
  uint8_t state = IDLE;
  uint16_t packetReceivedCount[4] = {0};
  uint16_t totalPacketSentCount = 0;
  /***  Module Variables Start ************************************/
  bool mModuleSleeping = FALSE;
  /* Packet Writing Variables */
  uint16_t packetCountWritten = 0;
  uint16_t packetCountRead = 0;
  uint16_t packetSentCount = 0;
  
  
  /* Data logging variables */
	typedef nx_struct flashLogEntry_t 
	{
    	nx_uint32_t timeStamp;
    	nx_uint16_t temperature;
    	//nx_uint16_t voltage;    	
		nx_float voltage;
    	nx_uint8_t srcNodeID;
    	nx_uint8_t sentStatus;
        nx_uint8_t probe;
        nx_uint8_t hopCount;
        nx_uint8_t dstNodeID;
  	} flashLogEntry_t;
    flashLogEntry_t mRemoteBufferedEntries[BUFFERED_PACKET_COUNT];
    uint8_t mRemoteBufferedEntriesIndex=0;

  	bool mLogBusy = FALSE;  	
    flashLogEntry_t mLocalEntry;
    flashLogEntry_t mRemoteEntry;
    uint16_t MAX_NUM_LOG_ENTRIES = 500;  /* Just for experimentation, not actual!*/
  
  /*  Temperature sensing variables */
  uint16_t mTemperatureReading = 0;
  bool mReadBusy = FALSE;
  
  /*  Packet sending variables */
  flashLogEntry_t mLocalLogEntry;
  flashLogEntry_t mLocalProbePkt;
  bool mSendBusy = FALSE;

  bool radioBusy = FALSE;
  message_t pkt;

  /* Used to print a float via printf */
  void printfFloat(float toBePrinted) {
     uint32_t fi, f0, f1, f2;
     char c;
     float f = toBePrinted;

     if (f<0){
       c = '-'; f = -f;
     } else {
       c = ' ';
     }

     // integer portion.
     fi = (uint32_t) f;

     // decimal portion...get index for up to 3 decimal places.
     f = f - ((float) fi);
     f0 = f*10;   f0 %= 10;
     f1 = f*100;  f1 %= 10;
     f2 = f*1000; f2 %= 10;
     printf("%c%ld.%d%d%d", c, fi, (uint8_t) f0, (uint8_t) f1,  
		(uint8_t) f2);
   }

  /*******************************************************/
  /* This is the code that is called when the system starts.*/
  event void Boot.booted()
  {
    state = RECEIVE;

    if (call LogWrite.erase() != SUCCESS) {
    }
    call AMControl.start();	
    mLocalProbePkt.probe = 1;
    mLocalProbePkt.srcNodeID = TOS_NODE_ID;
  }
  
  
  /***************************************************/
  /*  Flash Logger */
	
    event void LogRead.readDone(void* buf, storage_len_t len, error_t err) 
    {
		/* If the base station cares to do anything with the log, do it here */
	}
	
	event void LogWrite.eraseDone(error_t err) 
	{
	}
	event void LogWrite.appendDone(void* buf, storage_len_t len, 
                                 bool recordsLost, error_t err) 
    {
		/* If the base station cares to log these packets, do it here */
	}

 	event void LogRead.seekDone(error_t err) 
 	{
 	}

  	event void LogWrite.syncDone(error_t err) 
  	{
  	}
	
  /**************************************************/

 /****** AMC Start *********************************/
  
  event void AMControl.startDone(error_t err) {
  	
    //printf("AMCControl Start Done\n");
    //printfflush();
    if (err == SUCCESS) {
        printf("BaseStation started Radio\n");
        printfflush();
    }
    else {
      call AMControl.start();      
    }
  }

  event void AMControl.stopDone(error_t err) {
  }
	  
  event void AMSend.sendDone(message_t* msg, error_t error) {
    if (&pkt == msg && error == SUCCESS) {
    	flashLogEntry_t* lPacket = (flashLogEntry_t*)call Packet.getPayload(&pkt, sizeof (flashLogEntry_t));	
        printf("Base station sent response to node:%d\n", lPacket->srcNodeID);
        printfflush(); 
    }else{
    	
	}    
  }

  event message_t* Receive.receive(message_t* msg, void* payload, uint8_t len) {

	  flashLogEntry_t* btrpkt = (flashLogEntry_t*)payload;
	  flashLogEntry_t* lPacket;
  	  //printf("Received Packet\n");
      //printfflush();
      if (len == sizeof(flashLogEntry_t)) {

	     // If received Probe request packet, and I am in IDLE mode, then respond to Probe packet and move to RECEIVE mode and start RECEIVE mode timer
	     if(btrpkt->probe == 1) {
	         //TODO Send response to Probe request packet
	         printf("Received probe request from srcNodeID = %d.  Sending probe response\n",btrpkt->srcNodeID);
	         printfflush(); 		
			lPacket = (flashLogEntry_t*)call Packet.getPayload(&pkt, sizeof (flashLogEntry_t));						    		
			*lPacket = *btrpkt;
            lPacket->dstNodeID=TOS_NODE_ID;
			if (call AMSend.send(AM_BROADCAST_ADDR, &pkt, sizeof(flashLogEntry_t)) == SUCCESS) {
                call ReceiveTimer.startOneShot(RECEIVE_PERIOD);
			}else{
				printf("LogRead.readDone:AMSend failed\n");
				printfflush();
			}         
	     }else{
	        
	        printf("srcNodeID : %d Voltage: ", btrpkt->srcNodeID);
	        printfFloat(btrpkt->voltage);
	        printf("\n");
	        printfflush();
	        packetReceivedCount[btrpkt->srcNodeID]++;
	      }
	}
	return msg;
  }
  
  task void doPrintBufferedEntries() {
     mRemoteBufferedEntriesIndex--;
     while(mRemoteBufferedEntriesIndex != 0) {
         flashLogEntry_t tmpEntry = mRemoteBufferedEntries[mRemoteBufferedEntriesIndex--];

         //printf("Received Packet srcNodeID : %d Timestamp: %lu Voltage: ", tmpEntry.srcNodeID, tmpEntry.timeStamp);
	     //printfFloat(tmpEntry.voltage);
	     //printf("\n\n");
	     //printfflush();
     }
     printf("Total Packet Received Count = %d, %d, %d, %d\n\n",packetReceivedCount[0], packetReceivedCount[1], packetReceivedCount[2], packetReceivedCount[3]);
     printfflush(); 
  } 
  
  event void ReceiveTimer.fired(){
      post doPrintBufferedEntries();
  }

}
